#pragma once
#include "orangepch.h"
#include "Core.h"
#include "Orange/Log.h"
namespace Orange
{

    enum class ShaderDataType
    {
        None = 0,
        FLoat1,
        FLoat2,
        FLoat3,
        FLoat4,
        Int1,
        Int2,
        Int3,
        Int4,
        Mat3,
        Mat4,
        BOOL
    };

    static uint32_t GetShaderDataSize(ShaderDataType type)
    {
        switch (type)
        {
        case ShaderDataType::FLoat1:
            return 4 * 1;
        case ShaderDataType::FLoat2:
            return 4 * 2;
        case ShaderDataType::FLoat3:
            return 4 * 3;
        case ShaderDataType::FLoat4:
            return 4 * 4;
        case ShaderDataType::Int1:
            return 4 * 1;
        case ShaderDataType::Int2:
            return 4 * 2;
        case ShaderDataType::Int3:
            return 4 * 3;
        case ShaderDataType::Int4:
            return 4 * 4;
        case ShaderDataType::Mat3:
            return 4 * 3 * 3;
        case ShaderDataType::Mat4:
            return 4 * 4 * 4;
        case ShaderDataType::BOOL:
            return 4;
        }

        ORANGE_CORE_ASSERT(false, " unknown shader type ")
        return 0;
    }

    struct LayoutElement
    {
        uint32_t m_Size;
        ShaderDataType m_Type;
        uint32_t m_Offset;
        std::string m_Name;
        bool m_Normalized;

        static uint32_t GetCount(ShaderDataType type)
        {
            switch (type)
            {
            case ShaderDataType::FLoat1:
                return 1;
            case ShaderDataType::FLoat2:
                return 2;
            case ShaderDataType::FLoat3:
                return 3;
            case ShaderDataType::FLoat4:
                return 4;
            case ShaderDataType::Int1:
                return 1;
            case ShaderDataType::Int2:
                return 2;
            case ShaderDataType::Int3:
                return 3;
            case ShaderDataType::Int4:
                return 4;
            case ShaderDataType::Mat3:
                return 3 * 3;
            case ShaderDataType::Mat4:
                return 4 * 4;
            case ShaderDataType::BOOL:
                return 1;
            }

            ORANGE_CORE_ASSERT(false, " unknown shader type ")
            return 0;
        }

        LayoutElement(ShaderDataType type, const std::string &name, bool normalized = false) : m_Type(type), m_Size(GetShaderDataSize(type)), m_Name(name), m_Offset(0), m_Normalized(normalized)
        {
        }
    };

    class ShaderLayout
    {
    public:
        ShaderLayout() {}
        ShaderLayout(const std::initializer_list<LayoutElement> &elements) : m_Elements(elements)
        {
            ComputedLayout(); // 计算布局
        }
        ~ShaderLayout() = default;

        void ComputedLayout()
        {

            uint32_t offset = 0;
            m_Stride = 0;
            for (LayoutElement &element : m_Elements)
            {
                element.m_Offset = offset;
                offset += element.m_Size;
                m_Stride += element.m_Size;
            }
        }

        std::vector<LayoutElement>::iterator begin() { return m_Elements.begin(); };
        std::vector<LayoutElement>::iterator end() { return m_Elements.end(); };
        std::vector<LayoutElement> GetElement() const { return m_Elements; };
        uint32_t GetStride() const { return m_Stride; };

    private:
        std::vector<LayoutElement> m_Elements;
        uint32_t m_Stride; // 布局的长度
    };

    class VertexBuffer
    {
    public:
        virtual void Bind() = 0;
        virtual void UnBind() = 0;
        virtual void SetLayout(ShaderLayout &layout) = 0;
        virtual ShaderLayout &GetLayout() = 0;
        static Ref<VertexBuffer> Create(float *vertexs, uint32_t size);
    };
    class IndexBuffer
    {
    public:
        virtual void Bind() = 0;
        virtual void UnBind() = 0;
        virtual uint32_t GetCount() const = 0;
        static Ref<IndexBuffer> Create(uint32_t *indexes, uint32_t count);
    };
}